package org.meetunexpectedly.limit;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.meetunexpectedly.constant.RedisConstant;
import org.meetunexpectedly.entity.user.User;
import org.meetunexpectedly.exception.LimiterException;
import org.meetunexpectedly.holder.IPHolder;
import org.meetunexpectedly.util.RedisCacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;


/**
 * @Description: RequestLimit 切面类
 * @Author: pupil
 * @Date: 2024/09/13 下午 7:52
 */
@Aspect
@Component
public class RequestLimitAop {

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @Around("@annotation(requestLimit)")
    public Object restriction(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {
        // 获取当前请求的ip
        String ip = IPHolder.get();
        // 请求限制次数
        int limitCount = requestLimit.limitCount();
        // 警告消息
        String warningMsg = requestLimit.warningMsg();
        // 提示消息
        String promptMsg = requestLimit.promptMsg();
        // 限制时间
        long time = requestLimit.time();
        // 封禁时间
        long prohibitionTime = requestLimit.prohibitionTime();

        String key1 = RedisConstant.REQUEST_BLOCK_IP + ip;
        Object o1 = redisCacheUtil.get(key1);
        if (!ObjectUtils.isEmpty(o1)) {
            throw new LimiterException(promptMsg);
        }

        String key2 = RedisConstant.REQUEST_IP + ip;
        Object o2 = redisCacheUtil.get(key2);
        if (ObjectUtils.isEmpty(o2)) {
            redisCacheUtil.set(key2, 1, time);
        } else {
            if (Integer.parseInt(o2.toString()) == limitCount) {
                // 到底限制数量进行ip封禁
                redisCacheUtil.set(key1, ip, prohibitionTime);
                redisCacheUtil.del(key2);
                throw new LimiterException(warningMsg);
            }
            redisCacheUtil.increment(key2, 1);
        }

        Object proceed = joinPoint.proceed();

        if (proceed instanceof User) {
            User user = (User) proceed;

            if (!ObjectUtils.isEmpty(user)) {
                redisCacheUtil.del(key2);
            }
        }

        return proceed;
    }
}
